1   /*
2    * Copyright (C) 2010 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import com.google.caliper.BeforeExperiment;
20  import com.google.caliper.Benchmark;
21  import com.google.caliper.Param;
22  import com.google.common.base.Ascii;
23  import com.google.common.collect.Lists;
24  import com.google.common.primitives.Chars;
25  
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Random;
30  
31  /**
32   * Benchmarks for the ASCII class.
33   *
34   * @author Kevin Bourrillion
35   */
36  public class AsciiBenchmark {
37    private static String ALPHA =
38        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
39    private static String NONALPHA =
40        "0123456789`~-_=+[]{}|;:',.<>/?!@#$%^&*()\"\\";
41  
42    @Param({"20", "2000"}) int size;
43    @Param({"2", "20"}) int nonAlphaRatio; // one non-alpha char per this many chars
44    @Param boolean noWorkToDo;
45  
46    Random random;
47    String testString;
48  
49    @BeforeExperiment void setUp() {
50      random = new Random();
51  
52      int nonAlpha = size / nonAlphaRatio;
53      int alpha = size - nonAlpha;
54  
55      List<Character> chars = Lists.newArrayListWithCapacity(size);
56      for (int i = 0; i < alpha; i++) {
57        chars.add(randomAlpha());
58      }
59      for (int i = 0; i < nonAlpha; i++) {
60        chars.add(randomNonAlpha());
61      }
62      Collections.shuffle(chars, random);
63      char[] array = Chars.toArray(chars);
64      this.testString = new String(array);
65    }
66  
67    private char randomAlpha() {
68      return ALPHA.charAt(random.nextInt(ALPHA.length()));
69    }
70  
71    private char randomNonAlpha() {
72      return NONALPHA.charAt(random.nextInt(NONALPHA.length()));
73    }
74  
75    @Benchmark int asciiStringToUpperCase(int reps) {
76      String string = noWorkToDo
77          ? Ascii.toUpperCase(testString)
78          : testString;
79  
80      int dummy = 0;
81      for (int i = 0; i < reps; i++) {
82        dummy += Ascii.toUpperCase(string).length();
83      }
84      return dummy;
85    }
86  
87    @Benchmark int asciiCharSequenceToUpperCase(int reps) {
88      String string = noWorkToDo
89          ? charSequenceToUpperCase(testString)
90          : testString;
91  
92      int dummy = 0;
93      for (int i = 0; i < reps; i++) {
94        dummy += charSequenceToUpperCase(string).length();
95      }
96      return dummy;
97    }
98  
99    @Benchmark int stringToUpperCase(int reps) {
100     String string = noWorkToDo
101         ? testString.toUpperCase(Locale.US)
102         : testString;
103 
104     int dummy = 0;
105     for (int i = 0; i < reps; i++) {
106       dummy += string.toUpperCase(Locale.US).length();
107     }
108     return dummy;
109   }
110 
111   @Benchmark boolean equalsIgnoreCaseCharSequence(int reps) {
112     // This benchmark has no concept of "noWorkToDo".
113     String upperString = testString.toUpperCase();
114     CharSequence testSeq = new StringBuilder(testString);
115     CharSequence upperSeq = new StringBuilder(upperString);
116     CharSequence[] lhs = new CharSequence[] { testString, testSeq, testString, testSeq };
117     CharSequence[] rhs = new CharSequence[] { upperString, upperString, upperSeq, upperSeq };
118 
119     boolean dummy = false;
120     for (int i = 0; i < reps; i++) {
121       dummy ^= Ascii.equalsIgnoreCase(lhs[i & 0x3], rhs[i & 0x3]);
122     }
123     return dummy;
124   }
125 
126   @Benchmark boolean equalsIgnoreCaseStringOnly(int reps) {
127     // This benchmark has no concept of "noWorkToDo".
128     String lhs = testString;
129     String rhs = testString.toUpperCase();
130 
131     boolean dummy = false;
132     for (int i = 0; i < reps; i++) {
133       dummy ^= Ascii.equalsIgnoreCase(lhs, rhs);
134     }
135     return dummy;
136   }
137 
138   @Benchmark boolean equalsIgnoreCaseJDK(int reps) {
139     // This benchmark has no concept of "noWorkToDo".
140     String lhs = testString;
141     String rhs = testString.toUpperCase();
142 
143     boolean dummy = false;
144     for (int i = 0; i < reps; i++) {
145         dummy ^= lhs.equalsIgnoreCase(rhs);
146     }
147     return dummy;
148   }
149 
150   @Benchmark boolean isUpperCase(int reps) {
151     // This benchmark has no concept of "noWorkToDo".
152     char[] chars = testString.toCharArray();
153 
154     boolean dummy = false;
155     for (int i = 0; i < reps; i++) {
156       for (int n = 0; n < chars.length; n++) {
157         dummy ^= Ascii.isUpperCase(chars[n]);
158       }
159     }
160     return dummy;
161   }
162 
163   static String charSequenceToUpperCase(CharSequence chars) {
164     int length = chars.length();
165     StringBuilder builder = new StringBuilder(length);
166     for (int i = 0; i < length; i++) {
167       builder.append(Ascii.toUpperCase(chars.charAt(i)));
168     }
169     return builder.toString();
170   }
171 }